import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;
import java.time.Duration;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        if (false) {    // for refer
            HashMap<String, String> _map = new HashMap<>();
            ConcurrentHashMap<String, String> _cmap = new ConcurrentHashMap<>();
            _cmap.put("key1", "sdfsdf");
            _cmap.put("key2", "fdsfds");
            _map.put("key1", "sdfsdf");

            ReentrantLock reentrantLock = new ReentrantLock();
            reentrantLock.lock();
            reentrantLock.unlock();
        }

        {
            LockFreeHashMap<String, String> map = new LockFreeHashMap<>();
            map.put("key1", "value1");
            map.put("key2", "value2");
            System.out.println(map.get("key1"));
            map.remove("key1");
            map.put("key4", "value4");
            map.remove("key1");
            map.put("key3", "value3");
            System.out.println(map.get("key1"));
            System.out.println(map.get("key3"));
            System.out.println(map.get("key2"));
            System.out.println(map.get("key1"));
        }

        System.out.println();
        final int capacity = 4;
        final int threadNum = 8;
        final int opNum = 3000;

        final int round = 6;
        final boolean testGet = true;
        final boolean truncateBeforGet = false;
        final Integer collisionMod = null;
        final Integer treeifyThreshold = null;
        ConcurrentMapTest mapTest = new ConcurrentMapTest(threadNum);

        long lf_put = 0, lf_get = 0, cm_put = 0, cm_get = 0;
        for (int i = 0; i < round; i++) {
            System.gc();
            Thread.sleep(1000);

            ConcurrentMap<String, String> lockFreeMap = new LockFreeHashMap<>(capacity);
            ConcurrentMap<String, String> concurrentMap = new comparisonTest.ConcurrentHashMap<>(capacity - 1, 1.0f);
            if (treeifyThreshold != null)
                ((comparisonTest.ConcurrentHashMap<?, ?>) concurrentMap).setTreeifyThreshold(treeifyThreshold);
            else
                ((comparisonTest.ConcurrentHashMap<?, ?>) concurrentMap).disableTreeify();

            Duration duration = mapTest.simulatePut(opNum, lockFreeMap, false, collisionMod);
            System.out.println("Lock-Free map put time: " + duration.toMillis() + " ms");
            lf_put += duration.toMillis();
            Duration duration2 = mapTest.simulatePut(opNum, concurrentMap, false, collisionMod);
            System.out.println("ConcurrentHashMap put time: " + duration2.toMillis() + " ms");
            cm_put += duration2.toMillis();

            if (testGet) {
                if (truncateBeforGet)
                    ((LockFreeHashMap<?, ?>) lockFreeMap).truncate();
                Duration duration3 = mapTest.simulateGet(opNum, lockFreeMap);
                System.out.println("Lock-Free map get time: " + duration3.toMillis() + " ms");
                lf_get += duration3.toMillis();
                Duration duration4 = mapTest.simulateGet(opNum, concurrentMap);
                System.out.println("ConcurrentHashMap get time: " + duration4.toMillis() + " ms");
                cm_get += duration4.toMillis();
            }
            System.out.println();
        }
        System.out.println("Lock-Free map put average: " + lf_put / round + " ms");
        System.out.println("ConcurrentHashMap put average: " + cm_put / round + " ms");
        if (testGet) {
            System.out.println("Lock-Free map get average: " + lf_get / round + " ms");
            System.out.println("ConcurrentHashMap get average: " + cm_get / round + " ms");
        }
        mapTest.shutdown();
    }
}